package com.wnzt.baszh.util.common;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.jdbc.core.simple.ParameterizedRowMapper;

import oracle.jdbc.OracleResultSet;
import oracle.xdb.XMLType;

/** */
/**
 * 通用的Object包装类(类型问题，依然是个瓶颈，如果有好的解决方案请pm我)
 * 
 * 功能：查询对象类型或对象集合时的通用包装类
 * 
 * 
 */
public class ObjectMapper implements ParameterizedRowMapper {
    private Class clazz;
    private List<String> xmlColumnList=null;
    public ObjectMapper(Class clazz) {
        this.clazz = clazz;
    }
    public ObjectMapper(Class clazz,String[] xmlString) {
        this.clazz = clazz;
        if(xmlString!=null&&xmlString.length>0){
            xmlColumnList=new ArrayList<String>();
            for(String str:xmlString){
                xmlColumnList.add(str);
            }
        }
    }

    public Class getClazz() {
        return clazz;
    }
    /** */
    /**
     * 重写mapRow方法
     */
    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
        try {
            Map<String, String> map = new HashMap<String, String>();
            ResultSetMetaData md = rs.getMetaData();
            for (int i = 0; i < md.getColumnCount(); i++) {
                String columnName = md.getColumnName(i + 1);
                if (columnName == null)
                    columnName = "";
                map.put(columnName.toLowerCase(), columnName);
            }

            Object obj = clazz.newInstance();
            Field fields[] = obj.getClass().getDeclaredFields();

            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                if (field.getName().equals("serialVersionUID")
                        || map.get(field.getName().toLowerCase()) == null)
                    continue;
                // 暴力访问
                field.setAccessible(true);
                this.typeMapper(field, obj, rs);
                // 恢复默认
                field.setAccessible(false);
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /** */
    /**
     * 数据类型包装器
     * 
     * @param field
     *            目标属性
     * @param obj
     *            目标对象
     * @param rs
     *            结果集
     * @throws Exception
     */
    private void typeMapper(Field field, Object obj, ResultSet rs)
            throws Exception {
        String type = field.getType().getName();
        if (type.equals("java.lang.String")) {
            if(xmlColumnList!=null&&xmlColumnList.contains(field.getName())){
                OracleResultSet orset = (OracleResultSet) rs;
                if(orset.getOPAQUE(field.getName())!=null){
                    XMLType poxml = XMLType.createXML(orset.getOPAQUE(field.getName()));
                    field.set(obj, poxml.getStringVal());
                }
            }else
                field.set(obj, rs.getString(field.getName()));
        } else if (type.equals("int")) {
            field.set(obj, rs.getInt(field.getName()));
        } else if (type.equals("java.lang.Integer")) {
            if (rs.getString(field.getName()) == null
                    || "".equals(rs.getString(field.getName()))) {
                field.set(obj, null);
            } else {
                field.set(obj, rs.getInt(field.getName()));
            }
        } else if (type.equals("long")) {
            field.set(obj, rs.getLong(field.getName()));
        } else if (type.equals("java.lang.Long")) {
            if (rs.getString(field.getName()) == null
                    || "".equals(rs.getString(field.getName()))) {
                field.set(obj, null);
            } else {
                field.set(obj, rs.getLong(field.getName()));
            }
        } else if (type.equals("boolean") || type.equals("java.lang.Boolean")) {
            field.set(obj, rs.getBoolean(field.getName()));
        } else if (type.equals("java.util.Date")) {
            // field.set(obj, rs.getDate(field.getName()));
            field.set(obj, rs.getTimestamp(field.getName()));
        } else if (type.equals("double")||type.equals("java.lang.Double")) { // Double型包装 Added by LC

            field.set(obj, rs.getDouble(field.getName()));
        } else if (type.equals("float") || type.equals("java.lang.Float")) {
            field.set(obj, rs.getFloat(field.getName()));
        } else if (type.equals("[B")) {
            // field.set(obj, rs.getDate(field.getName()));
            if (rs.getBlob(field.getName()) != null) {
                InputStream in = rs.getBlob(field.getName()).getBinaryStream();
                byte[] buf = new byte[1024];
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int n = 0;
                while ((n = in.read(buf)) >= 0) {
                    baos.write(buf, 0, n);
                }
                in.close();
                field.set(obj,  baos.toByteArray());
                baos.close();
            }
        }
    }
}